/* LVGL Example project
 * 
 * Basic project to test LVGL on ESP32 based projects.
 *
 * This example code is in the Public Domain (or CC0 licensed, at your option.)
 *
 * Unless required by applicable law or agreed to in writing, this
 * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.
 */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_freertos_hooks.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "nvs_flash.h"
#include "esp_spiffs.h"
#include "esp_vfs.h"
#include "esp_log.h"
#include "freertos/event_groups.h"
#include "esp_err.h"

#include "page.h"
#include "http.h"
#include "dht11.h"
#include "adc.h"
#include "button.h"
#include "smqtt.h"
/* Littlevgl specific */
#include "lvgl/lvgl.h"
#include "lvgl_helpers.h"
#include "lv_port_indev.h"
#define PAGE_NEXT 35
#define PAGE_LAST 27
#define PAGE_ENTER 55
#define PAGE_SETING 1
/*********************
 *      DEFINES
 *********************/
#define TAG "blbl_tv"
#define LV_TICK_PERIOD_MS 1
extern INROOM wp;
extern xQueueHandle gpio_evt_queue ;
extern struct _blbl_sys_t blbl_sys_t;
/**********************
 *  STATIC PROTOTYPES
 **********************/
static void lv_tick_task(void *arg);
static void guiTask(void *pvParameter);
/**********************
 *   SPIFFS初始化
 **********************/
void HTTP_task(void *pvParameter)
{
	int i=0;
    while(1) 
	{
		i++;
		if(i%5==0)//十分钟
			get_fans();
		if(i%(60*12)==0)//12小时
		{
			get_weather();
			i=0;
		}
		vTaskDelay(1000*60 / portTICK_RATE_MS);//一分钟
    }
   vTaskDelete(NULL);
}
static void SPIFFS_Directory(char * path) {
	DIR* dir = opendir(path);
	assert(dir != NULL);
	while (true) {
		struct dirent*pe = readdir(dir);
		if (!pe) break;
		ESP_LOGI(__FUNCTION__,"d_name=%s d_ino=%d d_type=%x", pe->d_name,pe->d_ino, pe->d_type);
	}
	closedir(dir);
}
void All_init()
{
	ESP_LOGI(TAG, "Initializing SPIFFS");
	esp_vfs_spiffs_conf_t conf = {
		.base_path = "/spiffs",
		.partition_label = NULL,
		.max_files = 8,
		.format_if_mount_failed =true
	};
	esp_err_t ret =esp_vfs_spiffs_register(&conf);
	if (ret != ESP_OK) 
	{
		if (ret == ESP_FAIL)
			ESP_LOGE(TAG, "Failed to mount or format filesystem");
		else if (ret == ESP_ERR_NOT_FOUND)
			ESP_LOGE(TAG, "Failed to find SPIFFS partition");
		else
			ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)",esp_err_to_name(ret));
		return;
	}
	SPIFFS_Directory("/spiffs/");
	ESP_ERROR_CHECK( nvs_flash_init() );
	button_init();
	//adc_init();
	DHT11_init(25);
}
static void button_task(void* arg)
{
    static TickType_t startTick, endTick, diffTick;
	uint32_t io_num;
	BaseType_t press_key = pdFALSE;
	BaseType_t lift_key = pdFALSE;
	while (1) {
		//接收从消息队列发来的消息
		xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY);
		//记录下用户按下按键的时间点
		if (gpio_get_level(io_num) == 0) {
			press_key = pdTRUE;
			startTick = xTaskGetTickCount();
			//如果当前GPIO口的电平已经记录为按下，则开始减去上次按下按键的时间点
		} else if (press_key) {
			
			lift_key = pdTRUE;//记录抬升时间点
			endTick = xTaskGetTickCount();
            diffTick = endTick - startTick;
		}
		//仅仅当按下标志位和按键弹起标志位都为1时候，才执行回调
		if (press_key & lift_key) {
			press_key = pdFALSE;
			lift_key = pdFALSE;
			//如果大于1s则回调长按，否则就短按回调
			if (diffTick > 100) {
				if(io_num==35)
				blbl_sys_t.user_data=55;//切换
				ESP_LOGI("button", "按键%d长按触发回调",io_num);
			}else {

				if(io_num==0)//按键0
				blbl_sys_t.user_data=PAGE_SETING;//设置
				else if(blbl_sys_t.state.sys_button)//如果使用lvgl按键机制
				{
              		encoder_handler(io_num);					
				}
				else//切换页面
				{
					blbl_sys_t.user_data=io_num;	
				}
				ESP_LOGI("button", "按键%d短按触发回调",io_num);
				
			}
		}
	}

}
void app_main() { 
    All_init();
    xTaskCreatePinnedToCore(guiTask, "gui", 8000*2, NULL, 0, NULL, 1);
    xTaskCreate(button_task, "button_task", 1024*2, NULL, 8, NULL);
    xTaskCreate(&HTTP_task, "HTTP_task", 1024*10, NULL, 7, NULL);
}

/* Creates a semaphore to handle concurrent call to lvgl stuff
 * If you wish to call *any* lvgl function from other threads/tasks
 * you should lock on the very same semaphore! */
SemaphoreHandle_t xGuiSemaphore;
extern lv_obj_t * cont_head;
void page_switch()
{
		uint32_t user_data;
	    user_data=blbl_sys_t.user_data;
    	if(user_data)
    	{
        	blbl_sys_t.user_data=0;

        if(user_data==PAGE_LAST)//往前
        {
            if(blbl_sys_t.page->last!=NULL)
            {  
				blbl_sys_t.page->end();
                blbl_sys_t.page=blbl_sys_t.page->last;  
                ESP_LOGI("SYSTEM","界面%d",blbl_sys_t.page->index);   
                blbl_sys_t.page->start();           
            }
            else
            {
                ESP_LOGI("SYSTEM","已到界面尽头");
                return;                
            }
        }else if (user_data==PAGE_NEXT)//向后
        {
            if(blbl_sys_t.page->next!=NULL)
            {
				blbl_sys_t.page->end();
                ESP_LOGI("SYSTEM","切换菜单");
                ESP_LOGI("SYSTEM","界面%d",blbl_sys_t.page->index); 

                blbl_sys_t.page=blbl_sys_t.page->next;      
                blbl_sys_t.page->start();				            
            }
            else
            {
                ESP_LOGI("SYSTEM","已到界面尽头");
                return;                   
            }
        }else if(user_data==PAGE_ENTER)//切换模式
		{
			if(blbl_sys_t.state.sys_button)
			{
				if(blbl_sys_t.ico.lv_button!=NULL)
				lv_obj_del(blbl_sys_t.ico.lv_button);
				blbl_sys_t.state.sys_button=0;
			}
			else
			{
				blbl_sys_t.ico.lv_button = lv_label_create(cont_head, NULL);
    			lv_label_set_recolor(blbl_sys_t.ico.lv_button, true);
    			lv_label_set_text(blbl_sys_t.ico.lv_button, "#3CB371 " LV_SYMBOL_GPS);
    		//	lv_obj_set_pos(blbl_sys_t.lv_wifi,0,0);//设置坐标
				blbl_sys_t.state.sys_button=1;//lvgl模式				
			}

			
		}else if (user_data==PAGE_SETING)
		{
			static uint8_t set=1;
			if(set)
			{
				blbl_sys_t.state.sys_button=1;//使用lvgl按键机制
				page3_start();
				set=0;
			}else
			{
				blbl_sys_t.state.sys_button=0;//退出lvgl按键机制
				page3_end();
				set=1;
			}
			
			
		}
		
   	 }
}
static void guiTask(void *pvParameter) {
    
    (void) pvParameter;
    xGuiSemaphore = xSemaphoreCreateMutex();
    lv_init();
    lvgl_driver_init();
    static lv_color_t buf1[DISP_BUF_SIZE];
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    static lv_color_t buf2[DISP_BUF_SIZE];
#else
    static lv_color_t *buf2 = NULL;
#endif
    static lv_disp_buf_t disp_buf;
    uint32_t size_in_px = DISP_BUF_SIZE;
    lv_disp_buf_init(&disp_buf, buf1, buf2, size_in_px);
	
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);   
    disp_drv.flush_cb = disp_driver_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);  

    /* Create and start a periodic timer interrupt to call lv_tick_inc */
    const esp_timer_create_args_t periodic_timer_args = {
        .callback = &lv_tick_task,
        .name = "periodic_gui"
    };
    esp_timer_handle_t periodic_timer;
    ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));
    //按键初始化
    lv_port_indev_init();
    test_start();
    /* Create the demo application */
    //create_demo_application();
    while (1) {
		//vTaskDelay(10 / portTICK_RATE_MS);
        /* Try to take the semaphore, call lvgl related function on success */
		page_switch();
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
            lv_task_handler();
            xSemaphoreGive(xGuiSemaphore);
       }
    }

    /* A task should NEVER return */
    vTaskDelete(NULL);
}
static void lv_tick_task(void *arg) {
    (void) arg;
    lv_tick_inc(LV_TICK_PERIOD_MS);
}
